﻿using System;
using System.Collections.Generic;
using System.Configuration;
using System.IO;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading.Tasks;

namespace JkUtils
{

    public class JkConfig
    {
        private static readonly string filename = "config.ini";
        /// <summary>
        /// 为INI文件中指定的节点取得字符串
        /// </summary>
        /// <param name="lpAppName">欲在其中查找关键字的节点名称</param>
        /// <param name="lpKeyName">欲获取的项名</param>
        /// <param name="lpDefault">指定的项没有找到时返回的默认值</param>
        /// <param name="lpReturnedString">指定一个字串缓冲区，长度至少为nSize</param>
        /// <param name="nSize">指定装载到lpReturnedString缓冲区的最大字符数量</param>
        /// <param name="lpFileName">INI文件完整路径</param>
        /// <returns>复制到lpReturnedString缓冲区的字节数量，其中不包括那些NULL中止字符</returns>
        [DllImport("kernel32")]
        private static extern int GetPrivateProfileString(
            string lpAppName,
            string lpKeyName,
            string lpDefault,
            byte[] lpReturnedString,
            int nSize,
            string lpFileName
        );

        /// <summary>
        /// 修改INI文件中内容
        /// </summary>
        /// <param name="lpApplicationName">欲在其中写入的节点名称</param>
        /// <param name="lpKeyName">欲设置的项名</param>
        /// <param name="lpString">要写入的新字符串</param>
        /// <param name="lpFileName">INI文件完整路径</param>
        /// <returns>非零表示成功，零表示失败</returns>
        [DllImport("kernel32")]
        private static extern bool WritePrivateProfileString(
            string lpAppName,
            string lpKeyName,
            string lpString,
            string lpFileName
        );


        private static string CheckFile(string file)
        {
            if (file.JkNullOrEmpty()) file = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, filename);
            if (!File.Exists(file))
            {
                try
                {
                    var f =  File.Create(file);
                    f.Close();
                }
                catch (Exception err)
                {
                    throw new ApplicationException("创建配置文件失败:" + err.Message);
                }
            }

            return file;
        }

        /// <summary>
        /// 读取INI文件值
        /// </summary>
        /// <param name="Section">节点名</param>
        /// <param name="Key">键</param>
        /// <param name="def">未取到值时返回的默认值</param>
        /// <param name="filePath">INI文件完整路径</param>
        /// <returns>读取的值</returns>
        public static string ReadIniString(string Section,string Key,string Default="",string File="")
        {
            File = CheckFile(File);
            byte[] Buffer = new byte[65535];
            int bufLen = GetPrivateProfileString(Section, Key, Default, Buffer, Buffer.GetUpperBound(0), File);
            if (bufLen == 0) return Default;
            var encoding = GetTextFileEncodingType(File);
            string s = Encoding.GetEncoding(0).GetString(Buffer);
            s = s.Substring(0, bufLen);
            return s.TrimEnd('\0');
        }

        public static void WriteIniString(string Section, string Key,string Value,string File="")
        {
            File = CheckFile(File);
            if (!WritePrivateProfileString(Section, Key, Value, File))
            {
                throw (new ApplicationException("写Ini文件出错"));
            }
        }


        //读整数
        public int ReadIniInteger(string Section, string Ident, int Default, string File = "")
        {
            string intStr = ReadIniString(Section, Ident, Convert.ToString(Default),File);
            try
            {
                return Convert.ToInt32(intStr);
            }
            catch (Exception ex)
            {
                Console.WriteLine(ex.Message);
                return Default;
            }
        }

        //写整数
        public void WriteInteger(string Section, string Ident, int Value, string File = "")
        {
            WriteIniString(Section, Ident, Value.ToString(),File);
        }

        //读布尔
        public bool ReadBool(string Section, string Ident, bool Default, string File = "")
        {
            try
            {
                return Convert.ToBoolean(ReadIniString(Section, Ident, Convert.ToString(Default),File));
            }
            catch (Exception ex)
            {
                Console.WriteLine(ex.Message);
                return Default;
            }
        }

        //写Bool
        public void WriteBool(string Section, string Ident, bool Value, string File = "")
        {
            WriteIniString(Section, Ident, Convert.ToString(Value),File);
        }

        /// <summary>
        /// 写入application.config 配置
        /// </summary>
        /// <param name="settingName"></param>
        /// <param name="valueName"></param>
        public static void SaveConfig(string settingName, string valueName)
        {
            Configuration config = ConfigurationManager.OpenExeConfiguration(ConfigurationUserLevel.None);
            bool flag = ConfigurationManager.AppSettings[settingName] != null;
            if (flag)
            {
                config.AppSettings.Settings.Remove(settingName);
            }
            config.AppSettings.Settings.Add(settingName, valueName);
            config.Save(ConfigurationSaveMode.Modified);
            ConfigurationManager.RefreshSection("appSettings");
        }

        /// <summary>
        /// 获取application.config设置
        /// </summary>
        /// <param name="settingName"></param>
        /// <returns></returns>
        public static string GetConfig(string settingName)
        {
            string result;
            try
            {
                string settingString = ConfigurationManager.AppSettings[settingName].ToString();
                result = settingString;
            }
            catch (Exception)
            {
                result = null;
            }
            return result;
        }

        /// <summary>
        /// 获取文本文件的字符编码类型
        /// </summary>
        /// <param name="fileName"></param>
        /// <returns></returns>
        private static Encoding GetTextFileEncodingType(string fileName)
        {
            Encoding encoding = Encoding.Default;
            FileStream fileStream = new FileStream(fileName, FileMode.Open, FileAccess.Read);
            BinaryReader binaryReader = new BinaryReader(fileStream, encoding);
            byte[] buffer = binaryReader.ReadBytes((int)fileStream.Length);
            binaryReader.Close();
            fileStream.Close();
            if (buffer.Length >= 3 && buffer[0] == 239 && buffer[1] == 187 && buffer[2] == 191)
            {
                encoding = Encoding.UTF8;
            }
            else if (buffer.Length >= 3 && buffer[0] == 254 && buffer[1] == 255 && buffer[2] == 0)
            {
                encoding = Encoding.BigEndianUnicode;
            }
            else if (buffer.Length >= 3 && buffer[0] == 255 && buffer[1] == 254 && buffer[2] == 65)
            {
                encoding = Encoding.Unicode;
            }
            else if (IsUTF8Bytes(buffer))
            {
                encoding = Encoding.UTF8;
            }
            return encoding;
        }
        /// <summary>
        /// 判断是否是不带 BOM 的 UTF8 格式
        /// BOM（Byte Order Mark），字节顺序标记，出现在文本文件头部，Unicode编码标准中用于标识文件是采用哪种格式的编码。
        /// </summary>
        /// <param name="data"></param>
        /// <returns></returns>
        private static bool IsUTF8Bytes(byte[] data)
        {
            int charByteCounter = 1; //计算当前正分析的字符应还有的字节数 
            byte curByte; //当前分析的字节. 
            for (int i = 0; i < data.Length; i++)
            {
                curByte = data[i];
                if (charByteCounter == 1)
                {
                    if (curByte >= 0x80)
                    {
                        //判断当前 
                        while (((curByte <<= 1) & 0x80) != 0)
                        {
                            charByteCounter++;
                        }
                        //标记位首位若为非0 则至少以2个1开始 如:110XXXXX...........1111110X 
                        if (charByteCounter == 1 || charByteCounter > 6)
                        {
                            return false;
                        }
                    }
                }
                else
                {
                    //若是UTF-8 此时第一位必须为1 
                    if ((curByte & 0xC0) != 0x80)
                    {
                        return false;
                    }
                    charByteCounter--;
                }
            }
            if (charByteCounter > 1)
            {
                throw new Exception("非预期的byte格式");
            }
            return true;
        }

    }
}
